﻿using System.Net;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Moq;
using NUnit.Framework;

namespace RESTController
{
    [TestFixture]
    public class ResourceControllerTests
    {
        private FakeResourceController controller;
        private Mock<HttpContextBase> httpContext;
        private Mock<HttpRequestBase> request;
        private WebHeaderCollection webHeaderCollection;
        

        [SetUp]
        public void BeforeEachTest()
        {
            CreateNewControllerInstance();
            MockControllerContext();
            UsePagingShouldBeFalse();
        }

        private void AddModelStateError()
        {
            controller.ModelState.AddModelError("*", "Some error with model");
        }

        private void CreateNewControllerInstance()
        {
            controller = new FakeResourceController();
        }

        private void MockControllerContext()
        {
            request = new Mock<HttpRequestBase>();
            httpContext = new Mock<HttpContextBase>();
            httpContext.SetupGet(x => x.Request).Returns(request.Object);
            webHeaderCollection = new WebHeaderCollection();
            request.SetupGet(x => x.Headers).Returns(webHeaderCollection);
            controller.ControllerContext = new ControllerContext(httpContext.Object, new RouteData(), controller);
        }

        private void UseAjaxRequest()
        {
            webHeaderCollection.Add("X-Requested-With", "XMLHttpRequest");
        }

        private static void UsePagingShouldBeFalse()
        {
            RESTControllerSettings.Settings.UsePaging = false;
        }

        private static void UsePagingShouldBeTrue()
        {
            RESTControllerSettings.Settings.UsePaging = true;
        }

        [Test]
        public void Delete_WhenExceptionIsThrown_WithAjax_ThrowsException()
        {
            controller.DeleteShouldThrowException = true;
            UseAjaxRequest();
            Assert.Throws<HttpException>(() => controller.Delete(1));            
        }

        [Test]
        public void Delete_WhenSuccessful_WithAjax_ReturnsEmptyResult()
        {
            UseAjaxRequest();
            var result = controller.Delete(1);
            MvcAssert.IsActionResultOfType<EmptyResult>(result);
        }

        [Test]
        public void Index_WhenRequested_ShouldReturnView()
        {
            var result = controller.Index();
            MvcAssert.IsActionResultOfType<ViewResult>(result);
        }

        [Test]
        public void Index_WhenRequestedWithAjax_ShouldReturnPartialView()
        {
            UseAjaxRequest();
            var result = controller.Index();
            MvcAssert.IsActionResultOfType<PartialViewResult>(result);
        }

        [Test]
        public void List_WhenRequested_ShouldReturnView()
        {
            var result = controller.List(null);
            MvcAssert.IsActionResultOfType<ViewResult>(result);
        }

        [Test]
        public void List_WhenRequestedWithAjax_ShouldReturnPartialView()
        {
            UseAjaxRequest();
            var result = controller.List(null);
            MvcAssert.IsActionResultOfType<PartialViewResult>(result);
        }

        [Test]
        public void List_WhenUsePagingIsTrue_HasPagedListModel()
        {
            UsePagingShouldBeTrue();
            var result = (ViewResult)controller.List(null);
            MvcAssert.HasModelOfType<PagedList<FakeModel>>(result);
        }
        
        [Test]
        public void New_AsGet_ShouldReturnView()
        {
            var result = controller.New();
            MvcAssert.IsActionResultOfType<ViewResult>(result);
        }

        [Test]
        public void New_AsGet_ShouldHaveModel()
        {
            var result = (ViewResult)controller.New();
            var model = MvcAssert.HasModelOfType<FakeModel>(result);
            Assert.IsNotNull(model);
        }

        [Test]
        public void New_AsPost_WithoutError_ShouldRedirect()
        {
            var model = new FakeModel();
            var result = controller.New(model);
            MvcAssert.IsActionResultOfType<RedirectToRouteResult>(result);
        }

        [Test]
        public void New_AsPost_WithError_ReturnsView()
        {
            var model = new FakeModel();
            AddModelStateError();
            var result = controller.New(model);
            MvcAssert.IsActionResultOfType<ViewResult>(result);
        }

        [Test]
        public void New_AsPost_WithError_WithAjax_ReturnsPartialView()
        {
            var model = new FakeModel();
            AddModelStateError();
            UseAjaxRequest();
            var result = controller.New(model);
            MvcAssert.IsActionResultOfType<PartialViewResult>(result);
        }
    }
}
